package com.ayf.payment.game.api.task.pay;

import com.alibaba.fastjson.JSONObject;
import com.ayf.payment.game.api.channel.ChannelHandleFactory;
import com.ayf.payment.game.api.dto.MerchantPayOrderDTO;
import com.ayf.payment.game.api.service.MerchantPayOrderService;
import com.ayf.payment.game.api.type.MerchantPayOrderStatusEnum;
import com.ayf.payment.game.api.utils.DateUtils;
import com.ayf.payment.game.api.utils.SnowFlakeUtils;
import com.github.pagehelper.PageHelper;
import com.swwx.charm.commons.lang.utils.LogPortal;
import com.swwx.charm.zookeeper.exception.GetLockFailedException;
import com.swwx.charm.zookeeper.exception.ReleaseLockFailedException;
import com.swwx.charm.zookeeper.lock.DistributedLock;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.List;
import java.util.concurrent.CountDownLatch;


@Component
public abstract class PayProcessingQueryTask {

    // 查询代付处理中每页的大小 默认每页100条
    private final static int pageSize = 100;

    @Autowired
    private MerchantPayOrderService merchantPayOrderService;
    @Autowired
    private ChannelHandleFactory channelHandleFactory;

    /**
     *
     * @param distributedLock
     */
    protected void run(DistributedLock distributedLock) {
        boolean lock = false;
        String traceId = SnowFlakeUtils.getTraceId();
        String lockName = this.getClass().getSimpleName().concat(System.getenv("XY_GAME_PAY_LOCK_FLAG"));
        try {
            if (lock = distributedLock.getLock(lockName)) {
                LogPortal.info("{} >>> get lock and run {} ", traceId, lockName);
                MerchantPayOrderDTO merchantPayOrderQueryParam = new MerchantPayOrderDTO();
                merchantPayOrderQueryParam.setStatus(MerchantPayOrderStatusEnum.PAY_PROCESSING.getStatus());
                merchantPayOrderQueryParam.setQueryFlag(Integer.valueOf(1));
                //过滤爱游宝代付订单
                merchantPayOrderQueryParam.setNotChannelCode("ayb");
                int count = merchantPayOrderService.getTotalCount(merchantPayOrderQueryParam);
                LogPortal.info("{} >>> [{}]处理总条数[{}]", traceId, lockName, count);
                if (count <= 0) {
                    return;
                }
                int totalPage = count % pageSize == 0 ? (count / pageSize) : (count / pageSize) + 1;
                for (int i = 0; i < totalPage; i++) {
                    PageHelper.startPage(i,pageSize);
                    final List<MerchantPayOrderDTO> list = merchantPayOrderService.getProcessingMerchantPayOrderList(merchantPayOrderQueryParam);
                    LogPortal.info("{} >>> {} 开始处理商户代付订单处理中交易第[{}]页[{}]条记录",traceId, lockName,(i + 1),list.size());
                    //初始化信号
                    final CountDownLatch countDownLatch = new CountDownLatch(list.size());
                    for (final MerchantPayOrderDTO dto : list) {
                        submit(new Runnable() {
                            @Override
                            public void run() {
                                try {
                                    String childTraceId = SnowFlakeUtils.getTraceId();
                                    JSONObject inputParam = new JSONObject();
                                    inputParam.put("traceId",childTraceId);
                                    inputParam.put("channelCode",dto.getChannelCode());
                                    inputParam.put("merchant_order_no",dto.getMerchantOrderNo());
                                    inputParam.put("substitutePayConfigId",dto.getChannelId());
                                    JSONObject data =channelHandleFactory.getHandler(inputParam.getString("channelCode")).orderQuery(inputParam);
                                    if (data == null) {
                                        LogPortal.info("{} {} 商户ID[{}] 商户订单号[{}] 代付订单查询结果为空，继续查询", traceId,childTraceId,dto.getMerchantId(),dto.getMerchantOrderNo());
                                        return;
                                    }
                                    Integer status = data.getInteger("status");
                                    if (status == null){
                                        LogPortal.info("{} {} 商户ID[{}] 商户订单号[{}] 代付订单查询结果状态为空，继续查询", traceId,childTraceId,dto.getMerchantId(),dto.getMerchantOrderNo());
                                        return;
                                    }
                                    if (MerchantPayOrderStatusEnum.PAY_PROCESSING.getStatus().equals(status)){
                                        LogPortal.info("{} {} 商户ID[{}] 商户订单号[{}] 代付订单查询结果为处理中，继续查询", traceId,childTraceId,dto.getMerchantId(),dto.getMerchantOrderNo());
                                        return;
                                    }
                                    String channelOrderNo = data.getString("channelOrderNo");
                                    String failReason = data.getString("failReason");
                                    if (StringUtils.isNotEmpty(channelOrderNo) && StringUtils.isEmpty(dto.getChannelOrderNo())){
                                        dto.setChannelOrderNo(channelOrderNo);
                                    }
                                    Date nowDate = DateUtils.getNowDate();
                                    dto.setQueryFlag(Integer.valueOf(0));
                                    dto.setLastUpdateTime(nowDate);
                                    dto.setFinishTime(nowDate);
                                    dto.setStatus(status);
                                    dto.setFailReason(failReason);
                                    merchantPayOrderService.updateMerchantPayOrder(dto);
                                } catch (Exception e) {
                                    LogPortal.error("{} 商户ID[{}] 商户订单号[{}] 订单查询发生了{}异常，错误描述:{}", e, traceId,dto.getMerchantId(),dto.getMerchantOrderNo(),e.getClass().getName(),e.getMessage());
                                }finally {
                                    //线程执行完成之后标记信号表示完成
                                    countDownLatch.countDown();
                                }
                            }
                        });
                    }
                    //等待线程池任务执行完毕
                    countDownLatch.await();
                }
            } else {
                LogPortal.info("{} >>> {} do not get lock ", traceId, lockName);
            }
        } catch (GetLockFailedException e) {
            LogPortal.error("{} >>> [DISTRIBUTED_LOCK_ACQUIRE_FAILED_ZK] 分布式锁获取失败,锁名称为:{}", traceId, lockName);
            LogPortal.error("{} >>> {} 获取lock失败", e, traceId, lockName);
        } catch (Exception e) {
            LogPortal.error("{} >>> {} 任务执行出错 ", e, traceId, lockName);
        } finally {
            if (lock) {
                LogPortal.info(traceId + " >>> " + lockName + " finished.");
                try {
                    distributedLock.releaseLock(lockName);
                } catch (ReleaseLockFailedException e) {
                    LogPortal.error("{} >>> [DISTRIBUTED_LOCK_RELEASE_FAILED_ZK] 分布式锁释放失败,锁名称为:{}", traceId, lockName);
                    LogPortal.error("{} >>> {} 释放失败", e, traceId, lockName);
                }
            }
        }
    }

    protected abstract void submit(Runnable task);
}
